package com.zx.service.Impl;/**
 * Author:JasonZ
 * Data:2023/4/20
 */

import com.alibaba.fastjson.JSON;
import com.zx.constant.GoodsConstant;
import com.zx.dao.ECommerceGoodsDao;
import com.zx.entity.EcommerceGoods;
import com.zx.service.IAsyncGoodsService;
import com.zx.vo.GoodsInfo;
import com.zx.vo.SimpleGoodsInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @program: ecommerce-parent
 * @description:
 * @author: JasonZ
 * @create: 2023-04-20 09:55
 **/
@Service
@Slf4j
public class AsyncGoodsServiceImpl implements IAsyncGoodsService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private ECommerceGoodsDao goodsDao;

    /**
     * 入库
     * 条件：传进来的数据不能重复
     * 入库的商品 不能是数据库中已存在的
     *
     * @param goodsInfos
     * @param taskId
     */
    //  JoinPoint: 连接点对象，获取原方法的Signature 方法签名
    //  around:  ProceedingJoinPoint----> JoinPoint
    //  PointCut: 切入点
    //  advice : 增强处理  after before around afterThrowing  afterReturning
    @Override
    @Async("getAsyncExecutor") //设置指定的线程池
    public void asyncImportGoods(List<GoodsInfo> goodsInfos, String taskId) {
        log.info("async task running: [{}]", taskId);
        StopWatch watch = StopWatch.createStarted();//秒表对象
        //入库操作比较严谨 需要对参数数据进行校验
        //1.如果当前的goodsInfo中存在重复的商品，不保存直接返回，同时记录错误日志
        boolean isIllegal = false;
        // 有去重需求的时候，一般都会定义个Set集合
        // goods_category+brand_category+goods_name
        HashSet<String> goodsJoinInfos = new HashSet<>();// 存放联合索引去重
        ArrayList<GoodsInfo> filteredGoodsInfos = new ArrayList<>(); //存放过滤之后的数据

        //先校验传进来的数据有没有重复值
        for (GoodsInfo goods : goodsInfos) {
            // 基本条件的判断，直接跳过，不返回 过滤掉不符合条件的基本数据
            if (goods.getPrice() <= 0 || goods.getSupply() <= 0) {
                log.info("goods info is invalid :[{}]", JSON.toJSONString(goods));
                continue;
            }
            String jointInfo = String.format("%s,%s,%s",
                    goods.getGoodsCategory(),
                    goods.getBrandCategory(),
                    goods.getGoodsName());
            if (goodsJoinInfos.contains(jointInfo)) {
                //有重复值就抛出异常 并且跳出循环
                isIllegal = true;
                break;
            }
            goodsJoinInfos.add(jointInfo);
            filteredGoodsInfos.add(goods);
        }
        if (isIllegal || CollectionUtils.isEmpty(filteredGoodsInfos)) {
            watch.stop();
            log.error("import nothing :[{}]", JSON.toJSONString(filteredGoodsInfos));
            log.info("check and import goods done: [{}] ms", watch.getTime());
            //有重复值 或者数据为空
            throw new RuntimeException("import failed!");
        }
        //再校验传进来的数据 数据库中是否已经存在
        //使用过滤后的数据查询数据库
        List<EcommerceGoods> ecommerceGoods = filteredGoodsInfos.stream().map(EcommerceGoods::to).collect(Collectors.toList());
        //过滤掉已经存在的数据库商品
        List<EcommerceGoods> targetGoodsInfos = new ArrayList<>();
        for (EcommerceGoods g : ecommerceGoods) {
            //如果数据库中已存在商品 就跳出本次循环
            if (null != goodsDao.findFirstByGoodsCategoryAndBrandCategoryAndGoodsName(
                    g.getGoodsCategory(),
                    g.getBrandCategory(),
                    g.getGoodsName())) {
                log.error("the goods [{}] is aready exist", g.getGoodsName());
                continue;
            }
            //过滤掉已经存在的数据库商品
            targetGoodsInfos.add(g);
        }
        if (CollectionUtils.isEmpty(targetGoodsInfos)) {
            log.error("The goods stored in the dateBase already  exist");
            log.info("check and import goods done: [{}] ms", watch.getTime());
            throw new RuntimeException("import failed!");
        }
        //持久化最终过滤好的商品
        List<EcommerceGoods> saveGoods = goodsDao.saveAll(targetGoodsInfos);
        //把新入库的商品也加入redis中 存入的是简易商品信息 也就是封面商品信息
        //转成简易商品信息
        List<SimpleGoodsInfo> savaSimpleGoods = saveGoods.stream().map(EcommerceGoods::toSimple).collect(Collectors.toList());
        HashMap<String, String> map = new HashMap<>();
        //把商品信息存入map中
        savaSimpleGoods.forEach(s-> map.put(s.getId().toString(),JSON.toJSONString(s)));
        //存入redis
        stringRedisTemplate.opsForHash().putAll(GoodsConstant.REDIS_GOODS_INFO_KEY,map);
        log.info("save goods info to db and redis: [{}]",saveGoods.size());
        watch.stop();
        log.info("check and import goods done: [{}] ms",watch.getTime());
    }
}
